#include "systick.h"

#define MYSYSTICK_ENABLE() (SysTick->CTRL |= SysTick_CTRL_ENABLE)
#define MYSYSTICK_DISABLE() (SysTick->CTRL &= ~SysTick_CTRL_ENABLE)
#define MYSYSTICK_WAIT()                            \
    uint32_t ctrlVal;                               \
    do                                              \
    {                                               \
        ctrlVal = SysTick->CTRL;                    \
    } while (!(ctrlVal & SysTick_CTRL_COUNTFLAG) && \
             (ctrlVal & SysTick_CTRL_ENABLE))

uint32_t systick_per_ms = 0; // 1ms计数值
uint32_t systick_per_us = 0; // 1us计数值

void mySYSTICK_init(void)
{
    // 配置时钟源
    SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);

    // 将SYSTICK失能
    // SysTick->CTRL = SysTick_CTRL_ENABLE_Msk;
    MYSYSTICK_DISABLE();

    // 将val归零
    SysTick->VAL = 0;

    // 利用当前主频, 计算每秒或毫秒对应的计数值
    RCC_ClocksTypeDef RCC_clockStruct;
    RCC_GetClocksFreq(&RCC_clockStruct);
    systick_per_ms = RCC_clockStruct.HCLK_Frequency / 8 / 1000;
    systick_per_us = systick_per_ms / 1000;
}

// // 不完整计算，当前ms不可超过1860
// void mySYSTICK_delayMs(uint16_t ms) 
// {
//     if(us == 0)
//         return;

//     // 计算对应ms事件的计数值
//     uint32_t ticks = ms * systick_per_ms;

//     // 写入load值注意每轮计数实际是（LOAD + 1）次
//     SysTick->LOAD = ticks - 1;

//     // 将val归零
//     SysTick->VAL = 0;

//     // 启动定时器
//     MYSYSTICK_ENABLE();

//     // 判断标志位（计数溢出）
//     // SYSTICK有可能被其他代码中断导致中途关闭，导致本代码陷入死循环
//     while(
//         !(SysTick->CTRL & SysTick_CTRL_COUNTFLAG) // 当前计算值尚未溢出
//         && (SysTick->CTRL & SysTick_CTRL_ENABLE)) // 计数器仍然在工作
//     {
//     }
    
//     // 关闭计数器
//     MYSYSTICK_DISABLE();
// }

// 优化写法，可以超过1860ms
void mySYSTICK_delayMs(uint16_t ms)
{
    // 计算对应ms事件的计数值
    uint32_t ticks = ms * systick_per_ms;

    // 计算完整数的次数
    uint8_t conut = ticks >> 24;
    uint32_t remain_ticks = ticks & 0xFFFFFF;

    // 先重复执行完整计数周期
    if (conut > 0)
    {
        // 启动第一次完整计数
        SysTick->VAL = 0;
        SysTick->LOAD = 0xFFFFFF;
        // 启动定时器
        MYSYSTICK_ENABLE();

        // 每触发一次下溢, 就将count - 1
        // 直到count变成0
        while (conut > 0)
        {
            // 等待溢出
            MYSYSTICK_WAIT();
            // 溢出之后cycles--
            conut--;
        }
        // 关闭定时器
        MYSYSTICK_DISABLE();
    }

    // 补充最后一轮不完整计数
    if (remain_ticks == 0)
        return;

    SysTick->VAL = 0; // 将val归零
    SysTick->LOAD = remain_ticks - 1;
    MYSYSTICK_ENABLE(); // 启动定时器
    // 判断标志位(计数溢出)
    // SYSTICK有可能被其他代码或中断中途关闭, 导致本代码陷入死循环

    MYSYSTICK_WAIT();
    // 关闭计数器
    MYSYSTICK_DISABLE();
}

void mySYSTICK_delayUs(uint16_t us)
{
    if(us == 0)
        return;

    // 计算对应ms事件的计数值
    uint32_t ticks = us * systick_per_us;

    // 写入load值
    SysTick->LOAD = ticks - 1;

    // 将val归零
    SysTick->VAL = 0;

    // 启动定时器
    MYSYSTICK_ENABLE();

    // 判断标志位（计数溢出）
    // while(
    //     !(SysTick->CTRL & SysTick_CTRL_COUNTFLAG) // 当前计算值尚未溢出
    //     && (SysTick->CTRL & SysTick_CTRL_ENABLE)) // 计数器仍然在工作
    // {
    // }
    MYSYSTICK_WAIT();
    
    // 关闭计数器
    MYSYSTICK_DISABLE();
}
